/** 
 *  @file         basic_fsm_demo.c
 *  @brief        基础状态机实例、以及错误处理
 *  @author       Schips
 *  @date         2019-05-27 08:43:51
 *  @version      v1.0
 *  @copyright    Copyright By Schips, All Rights Reserved
 *
 **********************************************************
 */

#include <stdio.h>
#include "openfsm.h"

// 定义数据域
typedef struct {
    int cnt;
} SM_DATA;


/* ------------------- Functions -----------------------------*/
/* 状态机 函数指针 区域 */
void* step_init(void * this_fsm); // 初始化状态
void* step_do_something(void * this_fsm);//计数状态
void* step_done(void * this_fsm);// 执行完成状态
void* step_err(void* this_fsm);  // 错误状态

/* 状态ID ，顺序要求与 procedure_list[] 对应 */
enum procedure_id { state_init, state_count, state_done, state_err};
/* 状态机跳转列表 */
static Procedure procedure_list[] = { step_init, step_do_something, step_done, step_err};

void* step_init(void* this_fsm)
{
    SM_DATA *pd = get_data_entry(this_fsm);

    // 切换到下个状态
    set_next_state(this_fsm, state_count);

    // 数据处理
    pd->cnt = 0;

    return NULL;
}

void* step_do_something(void* this_fsm)//计数
{
    SM_DATA *pd = get_data_entry(this_fsm);

    pd->cnt++;

    if ( (pd->cnt) > 3)
    {
        set_next_state(this_fsm, state_err); // 故意进入错误状态
        //set_next_state(this_fsm, state_done);
    }

    return NULL;
}

void* step_done(void* this_fsm)//计数完成
{
    // 驻留
    set_next_state(this_fsm, state_done);
    return NULL;
}

void* step_err(void* this_fsm)// 错误状态
{
    int *err_var;
    // 驻留（实际上，若不修改状态，则一直重复当前状态）
    set_next_state(this_fsm, state_err);

    // 通知 调用者 有错误发生
    set_fsm_error_flag(this_fsm);

    // 把 错误值 设进 容器中（如果容器存在）
    err_var = get_err_var(this_fsm);
    if(err_var) 
        *err_var = 0xff;
    
    return NULL;
}

int main(void)
{
    int i = 10;
    // 状态机实例
    FSM fsm_1    = {0};
    // 状态机需要的数据实例
    SM_DATA data = {0};
    state cur_state;
    // 用于出错处理
    int err_code;
    int *got_err;

    // 设置 状态机
    set_procedures(&fsm_1, procedure_list);
    set_data_entry(&fsm_1, &data);
    set_default_state(&fsm_1, state_init);
    set_err_var(&fsm_1, &err_code);

    while(i--)
    {
        printf("=================\n");
        printf("Before runing: %d\n", get_curr_state(&fsm_1));

        // 执行状态机，使其步进一次
        cur_state = run_state_machine_once(&fsm_1);

        printf("Ran :%d\n", cur_state);
        printf("Next :%d\n", get_next_state(&fsm_1));

        // 判断是否出错
        if(is_fsm_error(&fsm_1))
        {
            printf("Error when Stepping !\n");
            got_err = get_err_var(&fsm_1);
            printf("Get Error Code :0x%x\n", *got_err);
            clr_fsm_error_flag(&fsm_1);
            break;
        }

        // 如果执行结束，则不再执行
        if(is_curr_state(&fsm_1, state_done))
        {
            printf("Done\n");
            reset_state_machine(&fsm_1);
            break;
        }
    }

    return 0;
}
